'''Provides the metadata necessary to plug-in to the Clutch
framework'''

import os
import sys
import logging

import pkg_resources

from paste.script.appinstall import Installer as PasteInstaller

log = logging.getLogger(__name__)

__all__ = ['entry', 'AppConfig' ]

class entry(object):

    def __init__(self, name, **kw):
        self.name = name
        self.kw = kw
        for k,v in kw.iteritems():
            setattr(self, k, v)

    def parse(self, package_name, subentry=None):
        if subentry is None:
            return parse_ep(package_name, self.name)
        else:
            return parse_ep(package_name, self.name, self.kw[subentry])

    def __repr__(self):
        l = [ '<Entry %s' % self.name ]
        for k,v in self.kw.iteritems():
            l.append('    %s=%s' % (k,v))
        l.append('>')
        return '\n'.join(l)
        

class AppConfig(object):
    '''This object configures the layout of the application package'''
    # Directories and sub-packages
    templates        = entry('templates')
    static_templates = entry('static_templates')
    public           = entry('public')
    commands         = entry('commands')
    model            = entry('model',
                             engine='engine',
                             metadata='metadata',
                             session='session')
    # Entry points
    root             = entry('controllers:Root')
    admin            = entry('controllers:Admin')
        
    def __init__(self, package_name):
        cls = self.__class__
        self.package_name = package_name
        self.package_ep = parse_ep(package_name)
        self.package = self.package_ep.load()
        self.templates = self.package_ep[cls.templates.name]
        self.static_templates = self.package_ep[cls.static_templates.name]
        self.public = self.package_ep[cls.public.name]
        self.commands = cls.commands.parse(package_name)
        if cls.model is not None:
            self.model = cls.model.parse(package_name)
            for k, v in cls.model.kw.iteritems():
                setattr(self, k, cls.model.parse(package_name, v))
        else:
            self.model = None
        self.root = cls.root.parse(package_name)
        self.admin = cls.admin.parse(package_name)

    def __repr__(self):
        l = ['<AppConfig %s' % self.package_name ]
        for k in dir(self):
            v = getattr(self, k)
            if not isinstance(k, entry): continue
            l.append('    ' + repr(k).replace('\n', '\n    '))
        l.append('>')
        return '\n'.join(l)

class ClutchInstaller(PasteInstaller):

    def config_content(self, command, vars):
        meta_name = 'clutch_deploy_%s_config.ini_tmpl' % self.clutch_application
        if not self.dist.has_metadata(meta_name):
            if command.verbose:
                print 'No %s found' % meta_name
            return self.simple_config(vars)
        return self.template_renderer(
            self.dist.get_metadata(meta_name), vars, filename=meta_name)

def parse_ep(*args):
    req = [args[0]]
    for arg in args[1:]:
        if not arg[0].isalpha():
            req.append(arg)
        req.append('.')
        req.append(arg)
    req = ''.join(req)
    if ':' in req:
        modname, objname = req.split(':')
        return ModuleEP(modname)[objname]
    else:
        modname = req
        return ModuleEP(modname)

class ModuleEP(object):

    def __init__(self, modname):
        self.modname = modname
        self.module = None

    def __getattr__(self, objname):
        return self[objname]

    def __getitem__(self, objname):
        return ObjectEP(self, objname)

    def load(self):
        if self.module is None:
            self.module = __import__(self.modname, fromlist=['None'])
        return self.module

    def resource_exists(self, path):
        return pkg_resources.resource_exists(self.modname, path)
    
    def resource_isdir(self, path):
        return pkg_resources.resource_isdir(self.modname, path)
    
    def resource_listdir(self, path):
        return pkg_resources.resource_listdir(self.modname, path)
    
    def resource_string(self, path):
        return pkg_resources.resource_string(self.modname, path)
    
    def resource_stream(self, path):
        return pkg_resources.resource_stream(self.modname, path)
    
    def __repr__(self):
        return '<ModuleEP for %s>' % self.modname

class ObjectEP(object):

    def __init__(self, module_ep, objname):
        self.module_ep, self.objname = module_ep, objname
        self.obj = None

    def load(self):
        if self.obj is None:
            module = self.module_ep.load()
            try:
                self.obj = getattr(module, self.objname)
            except AttributeError:
                log.exception('Error loading entry point %s', self)
                import pdb; pdb.set_trace()
                raise
        return self.obj

    def __call__(self, *l, **kw):
        return self.load()(*l, **kw)

    def resource_exists(self, path):
        return self.module_ep.resource_exists(self.objname + '/' + path)
    
    def resource_isdir(self, path):
        return self.module_ep.resource_isdir(self.objname + '/' + path)
    
    def resource_listdir(self, path):
        return self.module_ep.resource_listdir(self.objname + '/' + path)
    
    def resource_string(self, path):
        return self.module_ep.resource_string(self.objname + '/' + path)
    
    def resource_stream(self, path):
        return self.module_ep.resource_stream(self.objname + '/' + path)
    
    def __repr__(self):
        return '<ObjectEP for %s:%s>' % (self.module_ep, self.objname)

##def unload_module(modname):
##    for n in sys.modules.keys():
##        if n.startswith(modname):
##            del sys.modules[n]

